package com.henushang.ranking.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.conversions.Bson;

import com.henushang.ranking.constant.FieldConstant;
import com.mongodb.BasicDBObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Projections;
import com.mongodb.client.model.Sorts;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;

public interface BaseDao<T> {

    boolean insert(T t);

    T getOne(String _id);

    boolean delete(String _id);

    List<T> getListByQueryMap(Map<String, Object> queryMap);

    boolean update(T t);

    MongoCollection getColl();

    Document toDocument(T t);

    T fromDocument(Document document);

    String getCollectionName();

    default boolean updateById(T t) {
        Document document = toDocument(t);

        String id = document.getString("_id");
        if (StringUtils.isEmpty(id)) {
            return false;
        }
        Document query = new Document(FieldConstant.id, id);
        UpdateResult ur = getColl().replaceOne(query, document);
        return ur.getModifiedCount() > 0;
    }

    default boolean insertOne(T t) {
        Document document = toDocument(t);

        getColl().insertOne(document);
        return true;
    }

    default T findOneById(String id) {
        BasicDBObject query = new BasicDBObject();
        query.put("_id", id);
        Document document = (Document) getColl().find(query).first();
        return fromDocument(document);
    }

    default boolean deleteById(String id) {
        BasicDBObject query = new BasicDBObject();
        query.put("_id", id);
        DeleteResult result = getColl().deleteOne(query);
        return result.getDeletedCount() > 0;
    }

    default List<T> findList(Map<String, Object> queryMap) {

        return findListAndSort(queryMap, null);
    }

    default List<T> findListAndSort(Map<String, Object> queryMap, Bson sort) {
        BasicDBObject query = new BasicDBObject(queryMap);
        List<String> excludes = new ArrayList<>();
        excludes.add("content");

        FindIterable<Document> findIterable = getColl().find(query)
                .projection(Projections.exclude(excludes));
        if (sort != null) {
            findIterable.sort(sort);
        }

        return toList(findIterable);
    }

    default List<T> toList(FindIterable<Document> findIterable) {
        List<T> list = new ArrayList<>();
        for (Document document : findIterable) {
            list.add(fromDocument(document));
        }
        return list;
    }
}
